<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <!-- <div id="root">
    // 字符串
    <router-link to="apple"> to apple</router-link>
    // 对象
    <router-link :to="{path:'apple'}"> to apple</router-link>
    // 命名路由
    <router-link :to="{name: 'applename'}"> to apple</router-link>
    //直接路由带查询参数query，地址栏变成 /apple?color=red
    <router-link :to="{path: 'apple', query: {color: 'red' }}"> to apple</router-link>
    // 命名路由带查询参数query，地址栏变成/apple?color=red
    <router-link :to="{name: 'applename', query: {color: 'red' }}"> to apple</router-link>
    //直接路由带路由参数params，params 不生效，如果提供了 path，params 会被忽略
    <router-link :to="{path: 'apple', params: { color: 'red' }}"> to apple</router-link>
    // 命名路由带路由参数params，地址栏是/apple/red
    <router-link :to="{name: 'applename', params: { color: 'red' }}"> to apple</router-link>
  </div> -->

  <style>
  </style>
  <script>

    // VueRouter其实是一个插件，内部做了什么？
    // 1、实现并声明了两个全局注册组件：router-link和 router-view
    // 2、实现了install方法
    // 3、监控url变化:监听hashchange或popstate事件
    // 4、响应最新url:创建一个响应式的属性current，当它改变时获取对应组件并显示

    //Vue插件怎么写？ function/对象
    // 要求必须有一个install方法，将来被Vue调用
    let Vue; // 保存Vue的构造函数，在插件中使用
    class VueRouter {
      // 核心任务：1.监听url变化
      constructor(options) {
        this.$options = options;
        // 缓存path和route映射关系，这样找组件更快
        this.routerMap = {};
        this.$options.routes.forEach(route => {
          this.routerMap[route.path] = route;
        });
        // 数据响应式，定义一个响应式的current，则如果他变了，那么使用它的组件会rerender
        Vue.util.defineReactive(this, 'current', '')

        // 请确保onHashChange中this指向当前实例
        window.addEventListener('hashchange', this.onHashChange.bind(this))
        window.addEventListener('load', this.onHashChange.bind(this))
      }

      onHashChange() {
        // console.log(window.location.hash);
        this.current = window.location.hash.slice(1) || '/'
      }
    }

    // 插件需要实现install方法
    // 接收一个参数，Vue构造函数，主要用于数据响应式
    VueRouter.intall = (_Vue) => {
      // 保存Vue构造函数在VueRouter中使用
      Vue = _Vue;
      // 1、挂载$router属性
      // 全局混入(延迟下面的逻辑到router创建完毕并附加到选项才执行)
      Vue.mixin({
        beforeCreate() {
          // 注意此钩子在每个组件创建实例的时候都会调用
          // 根实例才有该选项
          if (this.$options.router) {
            vue.prototype.$router = this.$options.router;
          }
        }
      });

      // 2、实现两个全局组件
      Vue.component("router-link", {
        props: {
          to: {
            type: String,
            required: true
          },
        },
        render(h) {
          return h('a',
            { attrs: { herf: '#' + this.to } },
            this.$slots.default);
        }
      });
      Vue.component("router-view", {
        render(h) {
          // 根据current获取当前组件并render
          let component = null;
          const { current, routerMap } = this.$router;
          // 获取要渲染的组件
          if (routerMap[current]) {
            component = routerMap[current].component;
          }
          return h(component);
        }
      });

    }
    export default VueRouter;
  </script>
</body>

</html>